package rgr;

import rgr.GUI;
import process.Dispatcher;
import queues.QueueForTransactions;
import queues.Store;
import qusystem.MultiActor;
import stat.DiscretHisto;

//Клас моделі
public class Model implements widgets.experiments.IExperimentable, widgets.trans.ITransProcesable, Cloneable{
	//Посилання на диспетчера
	private Dispatcher dispatcher;
	//Посилання на візуальну частину
	private GUI gui;
	//Дробарка
	private Drob drob;
	//Екскалатор
	private Escs ecsc;
	//Самосид (оригінал для MultiActor)
	private Lorry lorry; 
	//Бригада самоскидів
	private MultiActor multiLorry; 
	//Купа каміння
	private Store heep; 
	//Черга самоскидів до екскалатора
	private QueueForTransactions queueToEcsc; 
	//Черга для самоскидів у дорозі
	private QueueForTransactions queueLorryOnRoad; 
	//Гістограма для довжини черги до навантажувача
	private DiscretHisto histoForQueueToEcsc;
	private DiscretHisto discretHisto;
	private double lastSumTime;
	private double sum;
	private double accumTime;
	
	//Создание модели////
	public Model(Dispatcher d, GUI g) {
		if (d == null || g == null) {
			System.out.println("Не визначено диспетчера або GUI для RgrModel");
			System.out.println("Подальша робота неможлива");
			System.exit(0);
		}
		dispatcher = d;
		gui = g;
		//Передаємо акторів до стартового списку диспетчера
		componentsToStartList();
	}
	//Получить обьект класса диспетчер////	
	public Dispatcher getDispatcher() {
		if(dispatcher==null){
			System.out.println("Не визначено диспетчера для моделі");
		}
		return dispatcher;
	}
//Установка обьекта класса диспетчер///	
	public void setDispatcher(Dispatcher newDispatcher) {
		dispatcher=newDispatcher;
		}
	//Получить ссылку на интерфейс/////
	public GUI getGui() {
		if(gui==null)System.out.println("Не визначено GUI для моделі");
		return gui;
	}
//Установить текущий интерфейс/////
	public void setGui(GUI gui) {
		this.gui = gui;
	}
/////////////////////////////////
	//Передаем актерев диспетчеру//////
	private void componentsToStartList() {
		// Передаємо акторів диспетчеру
		dispatcher.addStartingActor(getDrob());
		dispatcher.addStartingActor(getEscs());
		dispatcher.addStartingActor(getMultiLorry());
	}

	// ////////////////////////////////////////
	// Методи відкладеного створення акторів моделі,
	// ////////////////////////////////////////

// Дробарка
	public Drob getDrob() {
		if (drob == null) {
			drob = new Drob("Дробарка", gui, this);
		}
		return drob;
	}
// Ескаватор
	public Escs getEscs() {
		if (ecsc == null)
			ecsc = new Escs("Екскалатор", gui, this);
		return ecsc;
	}
// Получить определенное количество ескаваторов
	public MultiActor getMultiLorry() {
		if (multiLorry == null) {
			multiLorry = new MultiActor();
			multiLorry.setNameForProtocol("MultiActor для бригади самоскидів");
			multiLorry.setOriginal(getLorry());
			multiLorry.setNumberOfClones(gui.getChooseDataNLorry().getInt());
		}
		return multiLorry;
	}
// Самосвалы
	private Lorry getLorry() {
		if (lorry == null)
			lorry = new Lorry("Самоскид", gui, this);
		return lorry;
	}
// куча
	public Store getHeep() {
		if (heep == null) {
			heep = new Store();
			heep.setNameForProtocol("Купа каміння");
			heep.setDispatcher(dispatcher);
		}
		return heep;
	}

	// ////////////////////////////////////////
	// Методи відкладеного створення черг
	// ////////////////////////////////////////
// очередь самосвалов к ескаватору
	public QueueForTransactions getQueueToEcsc() {
		if (queueToEcsc == null) {
			queueToEcsc = new QueueForTransactions();
			queueToEcsc.setNameForProtocol("Черга до екскалатора");
			queueToEcsc.setDispatcher(dispatcher);
			queueToEcsc.setDiscretHisto(getHistoForQueueToEcsc());
		}
		return queueToEcsc;
	}
// очерь самосвалов что в дороге
	public QueueForTransactions getQueueLorryOnRoad() {
		if (queueLorryOnRoad == null) {
			queueLorryOnRoad = new QueueForTransactions();
			queueLorryOnRoad.setNameForProtocol("Cамоскиди, що у дорозі");
			queueLorryOnRoad.setDispatcher(dispatcher);
		}
		return queueLorryOnRoad;
	}

	// //////////////////////////////////////////////////////
	// Методи відкладеного створення накопичувачів статистики
	// //////////////////////////////////////////////////////
	//Гістограма для довжини черги до екскалатора
	public DiscretHisto getHistoForQueueToEcsc() {
		if (histoForQueueToEcsc == null) {
			histoForQueueToEcsc = new DiscretHisto();
			histoForQueueToEcsc.init();
		}
		return histoForQueueToEcsc;
	}

	// ///////////////////////////////////////////////////////////
	// Методи ініціалізації моделі
	// //////////////////////////////////////////////////////////////
	
	//Ініціалізація для режиму "Тест"
	public void initForTest() {
		// Передаємо чергам painter-ів для динамічної індикації
		getHeep().setPainter(gui.getDiagramHeepSize().getPainter());
		getQueueToEcsc().setPainter(
				gui.getDiagramQueueToEcsc().getPainter());
		getQueueLorryOnRoad().setPainter(
				gui.getDiagramLorryOnRoad().getPainter());
	}

	//Ініціалізація для режиму "Статистика"
	public void initForStat() {
		// Не виводити протокол на консоль
		dispatcher.setProtocolFileName("");
	}


///////////////////////////////////////////////////////////////
	public DiscretHisto getDiscretHisto() {
		if (discretHisto == null) {
			discretHisto = new DiscretHisto();
		}
		return discretHisto;
	}
	
	@Override
	public void initForExperiment(double factor) {
		getMultiLorry().setNumberOfClones((int) factor);
		getQueueToEcsc().init();
		getQueueLorryOnRoad().init();
		getQueueLorryOnRoad().setPainter(null);
		getQueueToEcsc().setPainter(null);
	//	gui.getChooseDataFinishTime().setText(String.valueOf(finishTime));
		//gui.getChooseDataNLorry().setText(String.valueOf(factor));
		if (gui.getJRadioButton().isSelected()){
			getQueueToEcsc().setDiscretHisto(getDiscretHisto());
			getDiscretHisto().init();
		} else
		{
		getQueueLorryOnRoad().setDiscretHisto(getDiscretHisto());
			getDiscretHisto().init();
	}
	}

	@Override
	public double getResultOfExperiment() {
		return getDiscretHisto().getAverage();
	}
	
	@Override
	public double getTransResult() {
		double dt = getDispatcher().getCurrentTime() - lastSumTime;
		lastSumTime = getDispatcher().getCurrentTime();
		sum += dt * getQueueToEcsc().size();
		accumTime += dt;
		return sum / accumTime;
	}

	@Override
	public void initForTrans(double finishTime) {
		getGui().getChooseDataFinishTime().setText(String.valueOf(finishTime));
		int modelID = hashCode();
		// Ініціалізуємо  купу
		getQueueToEcsc().init();
		getQueueToEcsc().setNameForProtocol("Черга машин" + modelID);
		getQueueToEcsc().setPainter(null);
		getMultiLorry().setNumberOfClones(gui.getChooseDataNLorry().getInt());
	}

	@Override
	public void resetTransAccum() {
		lastSumTime = getDispatcher().getCurrentTime();
		sum = 0;
		accumTime = 0;
	}
	
}
